package com.biz.primus.ms.oms.service.core;

import com.biz.primus.base.exception.BizSilentException;
import com.biz.primus.model.oms.enums.*;
import com.biz.primus.model.oms.enums.OrderState;
import com.biz.primus.model.oms.stream.OrderStateChannel.OrderStreamData;
import com.biz.primus.model.oms.vo.*;
import com.biz.primus.model.oms.vo.returns.RefundRequestVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.service.TransactionOptDelayer;
import com.biz.primus.ms.oms.dao.po.OmsOrder;
import com.biz.primus.ms.oms.dao.repository.OmsOrderRepository;
import com.biz.primus.model.oms.exception.OmsExceptions;
import com.biz.primus.ms.oms.service.channel.ChannelService;
import com.biz.primus.ms.oms.service.collection.OrderDataConverter;
import com.biz.primus.ms.oms.service.delivery.DeliveryStateService;
import com.biz.primus.ms.oms.stream.OrderStateSource;
import com.biz.primus.ms.oms.stream.RefundCollectionSource;
import com.biz.primus.ms.oms.vo.OmsOrderResource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Objects;

import static com.biz.primus.model.oms.enums.CancelType.none;
import static com.biz.primus.model.oms.enums.OrderState.*;

/**
 * @author yanweijin
 * @date 2017/11/6
 */

@Service
@Slf4j
public class OrderStateServiceImpl extends AbstractBaseService implements OrderStateService{


	@Autowired
	private OmsOrderRepository omsOrderRepository;

	@Autowired
	private TransactionOptDelayer transactionOptDelayer;

	@Autowired
	private OrderStateSource orderStateSource;

	@Autowired
	private DeliveryStateService deliveryStateService;

	@Autowired
	private OrderDataConverter orderDataConverter;

	@Autowired
	private RefundCollectionSource refundCollectionSource;

	@Autowired
	private ChannelService channelService;

	@Override
	public OmsOrder findOrder(OmsOrderResource req){
		if(req.getOrder()!=null){
			return req.getOrder();
		}else if(req.getOrderId() != null){
			return omsOrderRepository.findOne(req.getOrderId());
		}else if(req.getCode() != null){
			return omsOrderRepository.findByOrderCode(req.getCode());
		}else{
			throw new BizSilentException(OmsExceptions.ORDER_NOT_FOUNT);
		}
	}

	private OmsOrder findOrderWithDepot(OmsOrderResource req, String depotCode){
		OmsOrder order = findOrder(req);
		//不填写门店时,不检查
		if(StringUtils.isBlank(depotCode)){
			return order;
		}
		//如果填写了门店,检查订单是否属于门店
		if(Objects.equals(order.getDepotCode(),depotCode)){
			return order;
		}
		throw new BizSilentException(OmsExceptions.DEPOT_ERROR);
	}

	public void stateChange(OmsOrder order, OrderState newState, OrderState...oldStatus){
		if(order.getCancelType() != none){
			throw new BizSilentException(OmsExceptions.ORDER_CANCEL);
		}
		OrderState state = order.getState();
		if (Arrays.stream(oldStatus).anyMatch(state::equals)) {
			throw new BizSilentException(OmsExceptions.STATE_ERROR);
		}
		order.setState(newState);
		omsOrderRepository.save(order);
	}

	@Override
	public void backToBegin(OrderStateChangeRequest req, boolean sendMessage) {
		OmsOrder order = findOrder(req);
		stateChange(order, begin, allocated, printed);
		/*if(sendMessage){
			transactionOptDelayer.executeAfterTransactionCommit(()->{
				//重新通知分单
			});
		}*/
	}

	@Override
	public void allocateOrder(AllocationStateRequestVo req) {
		OmsOrder order = findOrder(req);
		order.setDepotCode(req.getTargetDepotCode());

		stateChange(order, allocated, begin);
		transactionOptDelayer.executeAfterTransactionCommit(()->{
			//通知门店有新订单 todo
		});
	}

	@Override
	public void printOrder(OrderStateChangeRequest req) {
		OmsOrder order = findOrderWithDepot(req,req.getDepot());
		stateChange(order, printed, allocated);
		transactionOptDelayer.executeAfterTransactionCommit(()->{
			//
		});

	}

	@Override
	public void outbound(OrderStateChangeRequest req) {
		OmsOrder order = findOrderWithDepot(req,req.getDepot());
		stateChange(order, outbound, printed);
		transactionOptDelayer.executeAfterTransactionCommit(()-> orderStateSource.orderOutboundOutput().send(buildMessage(order)));
	}

	@Override
	public void finishOrder(OrderStateChangeRequest req, OrderDeliveryState deliveryState) {
		OmsOrder order = findOrder(req);
		stateChange(order, finished, outbound);
		order.setDeliveryState(deliveryState);
		//todo 记录配送日志
		transactionOptDelayer.executeAfterTransactionCommit(()-> orderStateSource.orderFinishedOutput().send(buildMessage(order)));
	}

	private Message<OrderStreamData> buildMessage(OmsOrder order) {
		OrderStreamData data = new OrderStreamData();
		data.setOrderCode(order.getOrderCode());
		return MessageBuilder.withPayload(data).build();
	}

	@Override
	public void fillExpressInfo(FillExpressInfoRequest req) {
		OmsOrder omsOrder = omsOrderRepository.findByOrderCode(req.getCode());
		if(omsOrder.getCancelType() != CancelType.none){
			throw  new BizSilentException(OmsExceptions.STATE_ERROR);
		}
		//更新快递信息
		omsOrder.setExpressNumber(req.getExpressNumber());
		omsOrder.setExpectedExpressProviderText(req.getExpressProvider());
		omsOrder.setDeliveryState(OrderDeliveryState.distributing);
		omsOrderRepository.save(omsOrder);
	}

	@Override
	public void cashTransferPayment(String orderCode) {
		OmsOrder omsOrder = omsOrderRepository.findByOrderCode(orderCode);
		omsOrder.setPaymentState(OrderPaymentState.paid);
		omsOrder.setState(OrderState.finished);
		omsOrderRepository.save(omsOrder);
	}


	@Override
	public void changeConsigneeInfo(ChangeShippingInfoRequest req) {

		OmsOrder omsOrder = omsOrderRepository.findByOrderCode(req.getCode());
		OrderDeliveryType oldOrderDeliveryType = omsOrder.getDeliveryType();

		OrderState state = omsOrder.getState();
		if(state==begin || state == finished){
			throw new BizSilentException(OmsExceptions.STATE_ERROR);
		}
		if(state==outbound && req.getSource()== OrderOperatorSource.depot){
			throw new BizSilentException(OmsExceptions.STATE_ERROR);
		}

		//修改配送信息
		if(req.getDeliveryType()!=null){
			omsOrder.setDeliveryType(req.getDeliveryType());
		}
		if(req.getConsignee()!=null){
			omsOrder.setConsignee(orderDataConverter.consigneeVo2Po(req.getConsignee(),omsOrder.getId()));
		}
		omsOrderRepository.save(omsOrder);

		transactionOptDelayer.executeAfterTransactionCommit(()->{
			//如果配送方式与之前不一致 需要进行相应的操作
			if(oldOrderDeliveryType != req.getDeliveryType()){
				if(req.getDeliveryType()==OrderDeliveryType.take_their){
					//自提(需要生成自提码)
					deliveryStateService.generateToken(omsOrder);
				}else if(req.getDeliveryType().isSelfDelivery()){
					//自配送(需要通知配送APP)
					deliveryStateService.notifyDeliveryApp(omsOrder.getOrderCode());
				}
			}
		});
	}


	@Override
	public void cancelOrder(UserOrderOperationRequest req) {
		OmsOrder omsOrder =  omsOrderRepository.findByOrderCode(req.getOrderCode());
		if(Objects.isNull(omsOrder)){
			throw  new BizSilentException(OmsExceptions.ORDER_NOT_FOUNT);
		}
		if(omsOrder.getCancelType() != none){
			//已经被取消,直接结束方法
			return;
		}
		OrderState state = omsOrder.getState();
		//用户取消只能在拣货前(门店操作打印订单)
		if(state != begin && state != allocated){
			throw  new BizSilentException(OmsExceptions.STATE_ERROR);
		}
		omsOrder.setCancelType(CancelType.canceled);
		omsOrderRepository.save(omsOrder);

		transactionOptDelayer.executeAfterTransactionCommit(()->{
			//如果已支付,根据订单数据生成退款单vo,并发送流
			if(Objects.equals(omsOrder.getPaymentState(),OrderPaymentState.paid)){
				//获取渠道
				OmsChannelVo channel = channelService.findChannelByCode(omsOrder.getChannel());

				RefundRequestVo refundReq = new RefundRequestVo();
				refundReq.setOrderId(omsOrder.getId());
				refundReq.setReturnId(idService.getNextId());
				refundReq.setRefundAmount(omsOrder.getPaidAmount());
				if(channel.isOnlineChannel()){
					refundReq.setRefundNow(true);
					/*refundReq.setTradeNo();*/
				}else{
					refundReq.setRefundNow(false);
				}

				refundReq.setRemark("用户已支付取消订单，系统自动生成退款单");
				refundCollectionSource.refundDataOutput().send(MessageBuilder.withPayload(refundReq).build());
			}
		});
	}

	@Override
	public void closeOrder(OrderCloseRequest req) {
		OmsOrder omsOrder =  omsOrderRepository.findByOrderCode(req.getCode());

		if(Objects.isNull(omsOrder)){
			throw  new BizSilentException(OmsExceptions.ORDER_NOT_FOUNT);
		}

		if(omsOrder.getCancelType()!=none){
			//已经被取消,直接结束方法
			return;
		}

		//客服取消只能在出库前
		if(omsOrder.getState()==OrderState.outbound || omsOrder.getState()==OrderState.finished){
			throw  new BizSilentException(OmsExceptions.STATE_ERROR);
		}

		omsOrder.setSelfRemark(req.getRemark());
		omsOrder.setCancelType(CancelType.closed);
		omsOrderRepository.save(omsOrder);

		transactionOptDelayer.executeAfterTransactionCommit(()->{
			// 如果已支付,根据req和订单生成退款单vo,并发送流
			if(Objects.equals(omsOrder.getPaymentState(),OrderPaymentState.paid)){
				RefundRequestVo refundReq = new RefundRequestVo();
				refundReq.setOrderId(omsOrder.getId());
				refundReq.setReturnId(idService.getNextId());
				refundReq.setRefundAmount(omsOrder.getPaidAmount());
				refundReq.setOperator(req.getOperator());
				refundReq.setRefundWays(req.getRefundWays());
				refundReq.setRefundBank(req.getRefundBank());
				refundReq.setRefundBankAccount(req.getRefundBankAccount());
				refundReq.setRefundReceiver(req.getRefundReceiver());
				refundReq.setRemark(req.getRemark());
				refundCollectionSource.refundDataOutput().send(MessageBuilder.withPayload(refundReq).build());
		}
		});
	}
}
